package com.google.code.virtualhockey.vhx.server.model

import com.google.code.virtualhockey.vhx.sds.STMetaData
import com.google.code.virtualhockey.vhx.sds.fields._
import com.google.code.virtualhockey.vhx.sds.STNamedEntity
import java.util.Date
import com.google.code.virtualhockey.vhx.util.LangUtils

/**
 * General program parameter. This object is immutable. If you would like to change
 * a parameter value, please create a new ProgramParameter object with the same name
 * and save it to the database. It will replace the existing ProgramParameter object.
 */
class ProgramParameter( cpName: String,
                        cpValueType: ProgramParameterType.Value,
                        val value: Option[String] ) extends STNamedEntity[ProgramParameter] {

  setEntityName( cpName )

  private val _valueType = cpValueType.toString // persist enum as String
  def valueType() = ProgramParameterType.withName( _valueType )

  /** Returns the parameter value as String. */
  lazy val asString: Option[String] =
    if ( _valueType != ProgramParameterType.STRING )
      sys.error( "ProgramParameter '" + id().get.toString + "' is not of type " + ProgramParameterType.STRING.toString )
    else
      value

  /** Returns the parameter value as Long. */
  lazy val asLong: Option[Long] =
    if ( _valueType != ProgramParameterType.LONG )
      sys.error( "ProgramParameter '" + id().get.toString + "' is not of type " + ProgramParameterType.LONG.toString )
    else if ( value == None )
      None
    else
      Some( value.get.toLong )

  /** Returns the parameter value as Double. */
  lazy val asDouble: Option[Double] =
    if ( _valueType != ProgramParameterType.DOUBLE )
      sys.error( "ProgramParameter '" + id().get.toString + "' is not of type " + ProgramParameterType.DOUBLE.toString )
    else if ( value == None )
      None
    else
      Some( value.get.toDouble )

  /** Returns the parameter value as Date. */
  lazy val asDate: Option[Date] =
    if ( _valueType != ProgramParameterType.DATE )
      sys.error( "ProgramParameter '" + id().get.toString + "' is not of type " + ProgramParameterType.DATE.toString )
    else if ( value == None )
      None
    else
      LangUtils.stringToDate( value.get )

  /** Private no-arg constructor for SDS. */
  private def this() = this( null, null, None )

  /** Convenience constructor for a String parameter. */
  def this( name: String, value: String ) = this( name, ProgramParameterType.STRING, Some( value ) )
  
  /** Convenience constructor for a Long parameter. */
  def this( name: String, value: Long )   = this( name, ProgramParameterType.LONG, Some( value.toString ) )

  /** Convenience constructor for a Double parameter. */
  def this( name: String, value: Double ) = this( name, ProgramParameterType.DOUBLE, Some( value.toString ) )

  /** Convenience constructor for a Date parameter. */
  def this( name: String, value: Date )   = this( name, ProgramParameterType.DATE, LangUtils.dateToString( value ) )
}

object ProgramParameterMeta extends STMetaData[ProgramParameter] {
  val cls = classOf[ProgramParameter]
  val kind = "ProgramParameter"
  val fields = List(
    new SShortText( this, "_valueType", false, Some( "valueType" ) ),
    new SShortText( this, "value", false ) )

  /**
   * Creates a new ProgramParameter instance from a CSV file line.
   */
  override def fromCsv( values: List[Any] ): ProgramParameter = {
    new ProgramParameter( values(0).toString,
                          ProgramParameterType.withName( values(1).toString ),
                          getOptionalCsvValue( values(2).toString ) )
  }
}

/** Enumerates the allowed parameter value types. */
object ProgramParameterType extends Enumeration {
  val STRING = Value
  val LONG = Value
  val DOUBLE = Value
  val DATE = Value
}
